{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS -Wall #-}

--------------------------------------------------------------------------------
-- |
-- Module      :  WumpusExpr.Radian
-- Copyright   :  (c) Stephen Tetley 2012
-- License     :  BSD3
--
-- Maintainer  :  stephen.tetley@gmail.com
-- Stability   :  unstable
-- Portability :  GHC GeneralizedNewtypeDeriving
--
-- Numeric type for radian.
--
--------------------------------------------------------------------------------

module WumpusExpr.Radian
  (
    
    Radian
  , toRadian
  , fromRadian
  , d2r
  , r2d
  , circularModulo

  ) where


import Data.Fixed

--------------------------------------------------------------------------------
-- Radian


-- | Radian is represented with a distinct type. 
--
-- Newtype wrapper over Double.
--
-- Note for Eq and Ord Radian is cast to a Fixed E9.
-- 
newtype Radian = Radian { getRadian :: Double }
  deriving (Num,Floating,Fractional,Real,RealFrac,RealFloat)

instance Show Radian where
  showsPrec i (Radian a) = showsPrec i a


instance Eq Radian where
  (==) a b = toFE9 a == toFE9 b

instance Ord Radian where
  compare a b = toFE9 a `compare` toFE9 b
  (<=) a b    = toFE9 a <= toFE9 b




toFE9 :: Radian -> Fixed E9
toFE9 = realToFrac . getRadian


-- | Convert to radians.
--
toRadian :: Real a => a -> Radian 
toRadian = Radian . realToFrac


-- | Convert from radians.
--
fromRadian :: Fractional a => Radian -> a
fromRadian = realToFrac . getRadian


-- | Degrees to radians.
--
-- Degree type fixed to @Double@, compose @d2r@ with @realToFrac@ 
-- for @Float@ etc.
--
d2r :: Double -> Radian
d2r = Radian . realToFrac . (*) (pi/180)

-- | Radians to degrees.
--
-- Degree type fixed to @Double@, compose @r2d@ with @realToFrac@ 
-- for @Float@ etc.
--
r2d :: Radian -> Double
r2d = (*) (180/pi) . fromRadian


-- | Modulo a (positive) angle into the range @0..2*pi@.
--
circularModulo :: Radian -> Radian
circularModulo r = d2r $ dec + (fromIntegral $ i `mod` 360)
  where
    i       :: Integer
    dec     :: Double
    (i,dec) = properFraction $ r2d r
